﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace SqlMeth
{
    public class App
    {
        static void Main(string[] args)
        {
            ConfigSettings settings = null;
            string processor = null;
            string dbConnection = null;
            int action = -1;
            List<DbTable> tablesWithSProcs = null;

            if (args.Length == 0 || args[0] == "-?" || args[0] == "/?" || args[0] == "?")
            {
                Console.WriteLine("Welcome to SqlMeth. It turns your previously designed tables into stored procedures and more.");
                Console.WriteLine("Arguments:");
                Console.WriteLine("1. Processor: Enter \"SqlMetal\" for LINQ-to-SQL or \"EdmGen\" for "+
                    "\n   Entity Framework modeling (currently, \"EdmGen\" is NOT supported).");
                Console.WriteLine("2. Actions: Tell SqlMeth what to do. Each action is incremental," +
                    "\n   meaning it will do everything the prior would:");
                Console.WriteLine("\t+ Enter \'1\' to add control columns \"_CreatedBy\", \"_CreatedOn\", " +
                    "\n\t  \"_Disabled\", \"_LastUpdatedBy\", \"_LastUpdatedOn\" and \"_VerCol\"");
                Console.WriteLine("\t+ Enter \'2\' to add stored procedures previously dropping older stored procedures " +
                    "\n\t  generated by SqlMeth (using previous configuration settings, namely \"Avoid\")");
                Console.WriteLine("\t+ Enter \'3\' to create a view per table");
                Console.WriteLine("\t+ Enter \'4\' to create DBML using SqlMetal");
                Console.WriteLine("\t+ Enter \'5\' to modify DBML to wire stored procedures with tables");
                Console.WriteLine("3. SQL database connection: Enter a SQL connection string.");
                Console.WriteLine("\nEmpty arguments, \"-?\", \"/?\" or \"?\" will prompt this message.");
                Console.ReadLine();

                return;
            }

            if (args.Length == 3)
            {
                // Note: When "EdmGen" is supported, make code changes
                processor = "sqlmetal"; // = args[0].ToLower();

                // Get action from arguments
                action = int.Parse(args[1]);

                // Get connection from arguments
                dbConnection = args[2];
            }
            else
            {
                Console.WriteLine("Arguments have issues!");
                Console.ReadLine();

                return;
            }

            // Load settings of app
            try
            {

                try
                {
                    settings = LoadSettings("./config.xml");
                }
                catch (InvalidOperationException ioe)
                {
                    Console.WriteLine(string.Format("XML file is not properly formatted. See {0}", ioe.Message));
                }
            }
            catch (FileNotFoundException fne)
            {
                Console.WriteLine(string.Format("Couldn\'t find {0}. Terminating program.", fne.FileName));
                return;
            }

            Hallucinator hal = new Hallucinator(dbConnection, settings);
            IToolWrapper wrapper = null;

            if(processor == "sqlmetal")
                wrapper = new SqlMetalWrapper(settings.MetalSettings, dbConnection);
            else
                wrapper = new EdmGenWrapper();

            if (action >= 1)
            {
                // Add control columns
                Console.WriteLine("Adding columns!");
                hal.AddControlColumns();
                Console.WriteLine("Added columns!");
                
                if (action >= 2)
                {
                    // Add stored procedures
                    Console.WriteLine("Creating stored procedures, please wait.");
                    tablesWithSProcs = hal.GenerateStoredProcedures();
                    Console.WriteLine("Finished generating stored procedures");

                    if (action >= 3)
                    {
                        // Create a view per table. Drop old
                        Console.WriteLine("Creating views, please wait.");
                        hal.GenerateViews(hal.ListTables());
                        Console.WriteLine("Finished generating views");

                        if (action >= 4)
                        {
                            // Delete any previous DBML file/s
                            Console.WriteLine("Deleting DBML, please wait");
                            if (wrapper.DeleteOldModel())
                                Console.WriteLine("Deleted old DBML.");
                            else
                                Console.WriteLine("No DBML was deleted.");
                            // Create DBML using SqlMetal
                            Console.WriteLine("Executing SqlMetal, please wait.");
                            wrapper.ExecuteTool();
                            Console.WriteLine("Completed SqlMetal execution.");

                            if (action >= 5)
                            {
                                Console.WriteLine("Wiring DBML to use stored procedures on table actions...");
                                // Modify DBML file to wire stored procedures to tables
                                wrapper.WireProceduresToTables(tablesWithSProcs);
                                Console.WriteLine("Wired!");
                                Console.WriteLine("Modifying return type of \"SELECT\" statements");
                                // Modify DBML for read stored procedures to return the type of their tables
                                wrapper.ModifyReturnTypeOfReadSProcs(tablesWithSProcs);
                                Console.WriteLine("Modified!");
                            }
                        }
                    }
                }
            }
            Console.WriteLine("Completed program.");
            Console.ReadLine();
        }

        /// <summary>
        /// Loads the program's settings
        /// </summary>
        /// <param name="path">Path where the settings are located</param>
        /// <returns>An object representation of the settings</returns>
        static ConfigSettings LoadSettings(string path)
        {
            using (StreamReader reader = new StreamReader(path))
            {
                ConfigSettings settings = ConfigSettings.ParseFromFile(reader);
                return settings;
            }
        }
    }
}
